package com.iteaj.iot.server;

import com.iteaj.iot.FrameworkException;
import com.iteaj.iot.LifeCycle;
import com.iteaj.iot.SocketMessage;
import com.iteaj.iot.server.udp.UdpServerComponent;
import org.springframework.beans.factory.BeanInitializationException;

import java.util.*;

/**
 * 用来存储和获取设备组件{@link SocketServerComponent}
 * @see #getByPort(Integer) 通过端口获取
 * @see #getByClass(Class) 通过报文类型{@link SocketMessage}获取
 * @see #getTcpserverComponents() 获取TCP端口的设备组件列表
 * @see #getUdpServerComponents() 获取UDP端口的设备组件列表
 */
public class ServerComponentFactory implements LifeCycle {

    private List<TcpServerComponent> tcpserverComponents = new ArrayList<>();
    private List<UdpServerComponent> udpServerComponents = new ArrayList<>();
    private static final ServerComponentFactory instance = new ServerComponentFactory();
    private Map<Integer, SocketServerComponent> componentMap = new HashMap<>(8);
    private Map<Class<? extends SocketMessage>, SocketServerComponent> messageComponentMap = new HashMap(8);

    protected ServerComponentFactory() { }

    public static ServerComponentFactory getInstance() {
        return ServerComponentFactory.instance;
    }

    public List<TcpServerComponent> getTcpserverComponents() {
        return Collections.unmodifiableList(this.tcpserverComponents);
    }

    public List<UdpServerComponent> getUdpServerComponents() {
        return Collections.unmodifiableList(this.udpServerComponents);
    }

    public SocketServerComponent getByPort(Integer port) {
        return componentMap.get(port);
    }

    public SocketServerComponent getByClass(Class<? extends SocketMessage> messageClass) {
        return messageComponentMap.get(messageClass);
    }

    public ServerComponentFactory register(SocketServerComponent component) {
        if(component instanceof TcpServerComponent) {
            tcpserverComponents.add((TcpServerComponent) component);
        }

        if(component instanceof UdpServerComponent) {
            udpServerComponents.add((UdpServerComponent) component);
        }

        int port = component.config().getPort();
        if(port <= 0 || port > 65535)
            throw new BeanInitializationException("服务端组件: " + component.getName() + "使用错误的端口: " + port);

        // 已经有组件使用此端口, 抛出异常
        final SocketServerComponent serverComponent = componentMap.get(port);
        if(serverComponent != null) {
            throw new FrameworkException(serverComponent.getName()
                    + "和" + component.getName() + "使用同一个端口: " + component.config().getPort());
        }

        // 每种设备组件的报文类型不能为空, 且不能和其他的设备组件的报文相同
        Class<? extends SocketMessage> messageClass = component.getMessageClass();
        if(messageClass == null) {
            throw new FrameworkException("请指定组件的报文类型："
                    + component.getClass().getSimpleName()+"<M extend ServerMessage>");
        }

        componentMap.put(port, component);
        messageComponentMap.put(messageClass, component);

        return this;
    }

    public SocketServerComponent remove(Class<? extends SocketMessage> message) {
        SocketServerComponent serverComponent = this.messageComponentMap.remove(message);
        tcpserverComponents.remove(serverComponent);
        udpServerComponents.remove(serverComponent);

        return serverComponent;
    }

    public int size() {
        return this.tcpserverComponents.size() + this.udpServerComponents.size();
    }

    @Override
    public void start(Object config) {
        componentMap.values().forEach(item -> item.start(config));
    }

    @Override
    public void stop() {
        componentMap.values().forEach(item -> item.stop());
    }

}
